package rpc_client_server;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.Lock;

public class MyCallable implements Callable<String> {
  
      private final HashMap<String, String> kvStore;
      private Request req;
	  private Lock mutex;
	  private String response = null;
	  private File serverLog = null;
	  public String serverName; 

	  MyCallable(HashMap<String, String> _kvStore, 
			     Request _req,
			     Lock _mutex,
			     File _serverLog,
			     String theServerName)
	  {
	    kvStore = _kvStore;
	    req = _req;
	    mutex = _mutex;
	    serverLog = _serverLog;
	    serverName = theServerName;
	  }
	
	@Override
    public String call() throws Exception {
		  int len = req.args.length;
	      String clientRequest = req.type;
	      
	      mutex.lock();
	      
	      /** Generate a random delay between 0-1500 milliseconds 
	       *  - Necessary to test concurrency. 
	       *  - The server will fail to meet the client timeout 33.3%. */
	      //Thread.sleep((int)(Math.random()*1500)); 
	      
	      if(len!= 0){
		       if(req.type.equalsIgnoreCase("PUT") && len == 2)
		       {
		    	   clientRequest += " " + req.args[0] + " " + req.args[1];
		           this.kvStore.put(req.args[0], req.args[1]);
		           response = "Key-Value pair added to KV Store!";
		       } 
		       else if(req.type.equalsIgnoreCase("GET") && len == 1)
		       {
		    	   clientRequest += " " + req.args[0];
		           response = this.kvStore.get(req.args[0]);
		       } 
		       else if(req.type.equalsIgnoreCase("DELETE") && len == 2)
		       {
		    	   clientRequest += " " + req.args[0];
		           this.kvStore.remove(req.args[0]);
		           response = "Key-Value pair corresponding to key-" + req.args[0] + " deleted!"; 
		       }
		       else {
		    	   System.out.println("Functionality " + req.type + "not supported. response: null");
		       }
		  }
	      
	      /** Server sends garbage half the time. 
	       * - Necessary for testing robustness of the client. */
	      //if((int)(Math.random()*2) >= 1) {
	      //  response = "blah";
	      //}
	      
	      String logString = ("" + GetTimestamp()+ "  " + this.serverName + ": ... request:'" + clientRequest + "', response:'" + response + "'.\r\n"); 
	      UpdateServerLog(logString);
	      mutex.unlock();
	      return response;
    }
	
	/* Create a timestamp. */ 
	private Timestamp GetTimestamp() {
		Date date= new java.util.Date();
		return (new Timestamp(date.getTime()));
	}
	
	/* Update server log. */
	private void UpdateServerLog(String errString) {
		try {
			FileWriter fw = new FileWriter(serverLog, true);
			System.out.print(errString);
			fw.write(errString);
			fw.close();
		} catch (IOException e) {
			System.out.println(GetTimestamp() + " ... Failure to update serverlog!");
			e.printStackTrace();
		}
		return;
	}
} 